package com.ant.user.controller;

import com.alibaba.fastjson.JSON;
import com.ant.user.UserApplication;
import com.ant.user.dto.*;
import com.ant.user.entity.UserEntity;
import com.ant.user.mapper.UserMapper;
import com.ant.user.Service.JWTService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.ant.user.utils.GenerateString.generateAccount;
import static com.ant.user.utils.GenerateString.generatePassphrase;
import static com.ant.user.utils.PasswordUtil.*;

@RestController
@RequestMapping("/user")
public class UserController {
    @Value("${app.login-exceed}")
    long loginExceedTime;

    @Value("${app.fail-lock-time}")
    long failLockTime;

    @Autowired
    JWTService jwtService;

    @Autowired
    UserMapper userMapper;

    private static final Logger logger = LogManager.getLogger(UserApplication.class);


    //使用短信验证码进行注册
    @PostMapping("/register")
    public String RegisterByVerification(@RequestBody UserRegisterDTO userRegisterDTO)
    {

        Map<String, String> Payload = null;
        HashMap<String, Object> result = new HashMap<>();
        try {
            if(!jwtService.verifyToken(userRegisterDTO.getVerification()))
            {
                logger.error("签名验证错误");
                result.put("result", "请停止对本系统的攻击行为");
                result.put("data", "");
                result.put("status_code", 200);
                return JSON.toJSONString(result);
            }
            Payload = jwtService.decodeToken(userRegisterDTO.getVerification());
        } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException | SignatureException |
                 InvalidKeyException e) {
            logger.error("签名验证错误");
            result.put("result", "请停止对本系统的攻击行为");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }
        if(!Payload.get("type").equals("phone"))
        {
            result.put("result", "请停止对本系统的攻击行为");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        if(Long.parseLong(Payload.get("expire")) < (new Date()).getTime())
        {
            logger.error("手机号验证时间超限");
            result.put("result", "验证码时间超限");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }


        // 生成随机密码
        String passphrase = generatePassphrase(12);
        logger.info(passphrase);

        // 匹配该手机号是否发送过该验证码
        UserEntity userEntity = new UserEntity();
        userEntity.setAccount(generateAccount(16));
        userEntity.setPassphrase(hashPassphrase(passphrase));
        userEntity.setContact(Payload.get("phone"));
        userEntity.setFailCount(0);
        userEntity.setLastLoginTime(0);
        userEntity.setDropTime(9999999999999L);

        try {
            userMapper.Insert(userEntity);
        }catch (DuplicateKeyException e){
            logger.error("DuplicateKeyException: 使用重复号码进行注册，号码: " + Payload.get("phone"));
            result.put("result", "该号码已被注册");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        String jwt = null;

        // 生成访问令牌
        Map<String, String> JwtPayload = new HashMap<>();
        JwtPayload.put("account", userEntity.getAccount());
        JwtPayload.put("type", "login_jwt");
        JwtPayload.put("expire", String.valueOf((new Date()).getTime()) + loginExceedTime);

        try {
            jwt = jwtService.getToken(JwtPayload);
        } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException | SignatureException |
                 InvalidKeyException e) {
            result.put("result", "系统错误");
            result.put("data", "");
            result.put("status_code", 500);
            return JSON.toJSONString(result);
        }

        result.put("result", "注册成功");
        result.put("data", jwt);
        result.put("status_code", 200);
        return JSON.toJSONString(result);
    }


    @PostMapping("/login/verification")
    public String LoginByVerification(@RequestBody UserLoginDTO userLoginDTO)
    {
        Map<String, String> Payload = null;
        HashMap<String, Object> result = new HashMap<>();

        // 验证签名的正确性，验证数据被中途篡改
        try {
            if(!jwtService.verifyToken(userLoginDTO.getVerification()))
            {
                logger.error("签名验证错误");
                result.put("result", "请停止对本系统的攻击行为");
                result.put("data", "");
                result.put("status_code", 200);
                return JSON.toJSONString(result);
            }
            Payload = jwtService.decodeToken(userLoginDTO.getVerification());
        } catch (Exception e) {
            logger.error("签名验证错误");
            result.put("result", "请停止对本系统的攻击行为");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        if(!Payload.get("type").equals("phone"))
        {
            result.put("result", "请停止对本系统的攻击行为");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }


        UserEntity userEntity = userMapper.SelectByContact(Payload.get("phone"));

        // 验证号码是否已经注册，保证手机号不为空
        if(userEntity == null || Payload.get("phone") == null)
        {
            logger.error("用户尝试使用不存在的手机号进行登录号码: " + Payload.get("phone"));
            result.put("result", "该号码未被注册");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        // 检查验证信息是否超时
        if(Long.parseLong(Payload.get("expire")) < (new Date()).getTime())
        {
            userEntity.setFailCount(userEntity.getFailCount()+1);
            userEntity.setLastLoginTime((new Date()).getTime() + failLockTime);
            userMapper.Update(userEntity);
            result.put("result", "验证码时间超限");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        // 预防暴力破解
        if(userEntity.getFailCount() >= 5 && userEntity.getLastLoginTime() > (new Date()).getTime())
        {
            result.put("result", "登录错误次数过多，请于24小时之后再试");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        // 登录成功，删除之前的操作错误信息
        userEntity.setLastLoginTime((new Date()).getTime());
        userEntity.setFailCount(0);
        userMapper.Update(userEntity);


        // 生成访问令牌
        Map<String, String> JwtPayload = new HashMap<>();
        JwtPayload.put("account", userEntity.getAccount());
        JwtPayload.put("type", "login_jwt");
        JwtPayload.put("expire", String.valueOf((new Date()).getTime()) + loginExceedTime);

        String jwt = null;
        try {
            jwt = jwtService.getToken(JwtPayload);
        } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException | SignatureException |
                 InvalidKeyException e) {
            result.put("result", "系统错误");
            result.put("data", "");
            result.put("status_code", 500);
        }

        result.put("result", "登录成功");
        result.put("data", jwt);
        result.put("status_code", 200);
        return JSON.toJSONString(result);
    }

    @PostMapping("/login/passphrase")
    public String LoginByPassphrase(@RequestBody UserLoginDTO userLoginDTO)
    {
        HashMap<String, Object> result = new HashMap<>();
        UserEntity userEntity = userMapper.SelectByContact(userLoginDTO.getContact());

        // 验证号码是否已经注册，保证手机号不为空
        if(userEntity==null || userLoginDTO.getContact()==null)
        {
            logger.error("用户尝试使用不存在的手机号进行登录密码修改操作， 号码: " + userLoginDTO.getContact());
            result.put("result", "该号码未被注册");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        // 预防暴力破解
        if(userEntity.getFailCount() >= 5 && userEntity.getLastLoginTime() > (new Date()).getTime())
        {
            result.put("result", "登录错误次数过多，请于24小时之后再试");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        // 检查密码是否正确
        try {
        if(!verifyPassphrase(userLoginDTO.getPassphrase(), userEntity.getPassphrase())) {
            userEntity.setFailCount(userEntity.getFailCount() + 1);
            userEntity.setLastLoginTime((new Date()).getTime() + failLockTime);
            userMapper.Update(userEntity);
            result.put("result", "密码错误");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }
        }catch(Exception e){
            result.put("result", "密码错误");
            result.put("data", "");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
            }

        // 登录成功，删除之前的操作错误信息
        userEntity.setLastLoginTime((new Date()).getTime());
        userEntity.setFailCount(0);
        userMapper.Update(userEntity);

        // 生成访问令牌
        Map<String, String> JwtPayload = new HashMap<>();
        JwtPayload.put("account", userEntity.getAccount());
        JwtPayload.put("type", "login_jwt");
        JwtPayload.put("expire", String.valueOf((new Date()).getTime()) + loginExceedTime);

        String jwt = null;
        try {
            jwt = jwtService.getToken(JwtPayload);
        } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException | SignatureException |
                 InvalidKeyException e) {
            result.put("result", "系统错误");
            result.put("data", "");
            result.put("status_code", 500);
        }

        result.put("result", "登录成功");
        result.put("data", jwt);
        result.put("status_code", 200);
        return JSON.toJSONString(result);
    }


    @PostMapping("/modification/passphrase/passphrase")
    public String UpdatePassphraseByPassphrase(@RequestBody UserWithConfirm userWithConfirm)
    {
        HashMap<String, Object> result = new HashMap<>();
        try {
            if(!jwtService.verifyToken(userWithConfirm.getToken()))
            {
                result.put("result", "禁止攻击本系统");
                result.put("status_code", 200);
                return JSON.toJSONString(result);
            }
        }
        catch (Exception e)
        {
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        Map<String, String> Payload = jwtService.decodeToken(userWithConfirm.getToken());
        UserEntity userEntity = userMapper.SelectByAccount(Payload.get("account"));
        if(!Payload.get("type").equals("login_jwt"))
        {
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        // 预防暴力破解
        if(userEntity.getFailCount() >= 5 && userEntity.getLastLoginTime() > (new Date()).getTime())
        {
            result.put("result", "原密码错误次数过多，请于24小时之后再试");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        if(!verifyPassphrase(userWithConfirm.getPassphrase(), userEntity.getPassphrase()))
        {
            userEntity.setFailCount(userEntity.getFailCount()+1);
            userEntity.setLastLoginTime((new Date()).getTime() + failLockTime);
            userMapper.Update(userEntity);
            result.put("result", "原密码错误");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        if(!validatePassphrase(userWithConfirm.getNextPassphrase()))
        {
            result.put("result", "新密码过于简单，请包含大小写字母，数字，-+_=");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        userEntity.setPassphrase(hashPassphrase(userWithConfirm.getNextPassphrase()));

        userMapper.Update(userEntity);

        result.put("result", "密码重置成功");
        result.put("status_code", 200);

        return JSON.toJSONString(result);
    }

    @PostMapping("/modification/passphrase/verification")
    public String UpdatePassphraseByVerification(@RequestBody ModifyPassphraseDTO modifyPassphraseDTO)
    {

        /*
        验证token是否完整
        从token中提取信息
        */
        HashMap<String, Object> result = new HashMap<>();
        try {
            if(!jwtService.verifyToken(modifyPassphraseDTO.getToken())
                    || !jwtService.verifyToken(modifyPassphraseDTO.getVerification()))
            {
                result.put("result", "禁止攻击本系统");
                result.put("status_code", 200);
                return JSON.toJSONString(result);
            }
        }
        catch (Exception e)
        {
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }
        Map<String, String> Payload = jwtService.decodeToken(modifyPassphraseDTO.getToken());
        if(!Payload.get("type").equals("login_jwt"))
        {
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        UserEntity userEntity = userMapper.SelectByAccount(Payload.get("account"));
        if(userEntity == null)
        {
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }
        if(!userEntity.getContact().equals(jwtService.decodeToken(modifyPassphraseDTO.getVerification()).get("phone")))
        {
            userEntity.setFailCount(userEntity.getFailCount()+1);
            userEntity.setLastLoginTime((new Date()).getTime() + failLockTime);
            userMapper.Update(userEntity);
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        if(!validatePassphrase(modifyPassphraseDTO.getNextPassphrase()))
        {
            result.put("result", "新密码过于简单，请包含大小写字母，数字，-+_=");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        userEntity.setPassphrase(hashPassphrase(modifyPassphraseDTO.getNextPassphrase()));

        userMapper.Update(userEntity);

        result.put("result", "密码重置成功");
        result.put("status_code", 200);

        return JSON.toJSONString(result);
    }

    @PostMapping("/modification/contact")
    public String modificationContactByVerification(@RequestBody ModifyContactDTO modifyContactDTO){
        HashMap<String, Object> result = new HashMap<>();
        try {
            if(!jwtService.verifyToken(modifyContactDTO.getToken())
                    || !jwtService.verifyToken(modifyContactDTO.getLastContactVerification())
                    || !jwtService.verifyToken(modifyContactDTO.getNextContactVerification()))
            {
                result.put("result", "禁止攻击本系统");
                result.put("status_code", 200);
                return JSON.toJSONString(result);
            }
        }
        catch (Exception e)
        {
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }
        Map<String, String> Payload = jwtService.decodeToken(modifyContactDTO.getToken());
        if(!Payload.get("type").equals("login_jwt"))
        {
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        UserEntity userEntity = userMapper.SelectByAccount(Payload.get("account"));


        if(!userEntity.getContact().equals(jwtService.decodeToken(modifyContactDTO.getLastContactVerification()).get("phone")))
        {
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }
        UserEntity userEntityToFilter = userMapper.SelectByContact(jwtService.decodeToken(modifyContactDTO.getNextContactVerification()).get("phone"));
        if(userEntityToFilter != null)
        {
            result.put("result", "新号码已存在");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        userEntity.setContact(jwtService.decodeToken(modifyContactDTO.getNextContactVerification()).get("phone"));
        userMapper.Update(userEntity);
        result.put("result", "联系方式修改成功");
        result.put("status_code", 200);
        return JSON.toJSONString(result);
    }

    @PostMapping("/unregistered")
    public String UnregisterByVerification(@RequestBody DropUserDTO dropUserDTO)
    {
        HashMap<String, Object> result = new HashMap<>();
        try {
            if(!jwtService.verifyToken(dropUserDTO.getToken())
                    || !jwtService.verifyToken(dropUserDTO.getContactVerification()))
            {
                result.put("result", "禁止攻击本系统");
                result.put("status_code", 200);
                return JSON.toJSONString(result);
            }
        }
        catch (Exception e)
        {
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        Map<String, String> Payload = jwtService.decodeToken(dropUserDTO.getToken());
        if(!Payload.get("type").equals("login_jwt"))
        {
            result.put("result", "禁止攻击本系统");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        UserEntity userEntity = userMapper.SelectByAccount(Payload.get("account"));
        if(!userEntity.getContact().equals(jwtService.decodeToken(dropUserDTO.getContactVerification()).get("phone")))
        {
            logger.info(jwtService.decodeToken(dropUserDTO.getContactVerification()).get("phone"));
            result.put("result", "手机号与预留手机号不匹配");
            result.put("status_code", 200);
            return JSON.toJSONString(result);
        }

        userEntity.setDropTime((new Date()).getTime());
        userMapper.Update(userEntity);

        result.put("result", "注销成功");
        result.put("status_code", 200);
        return JSON.toJSONString(result);
    }
}
